package com.xbts.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xbts.common.config.XbtsConfig;
import com.xbts.common.constant.Constants;
import com.xbts.common.constant.UserConstants;
import com.xbts.common.core.domain.model.LoginUser;
import com.xbts.common.enums.EmailTypeEnum;
import com.xbts.common.enums.ShoppingCarEnums;
import com.xbts.common.exception.ServiceException;
import com.xbts.common.utils.DateUtils;
import com.xbts.common.utils.SecurityUtils;
import com.xbts.common.utils.StringUtils;
import com.xbts.common.utils.WordUtils;
import com.xbts.system.domain.*;
import com.xbts.system.domain.dto.CnContractManagerDTO;
import com.xbts.system.domain.dto.EmailSendDTO;
import com.xbts.system.domain.vo.CnContractManagerVO;
import com.xbts.system.domain.vo.SysUserControlVO;
import com.xbts.system.enums.OrderStatusEnum;
import com.xbts.system.mapper.CnContractManagerMapper;
import com.xbts.system.service.*;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 合同管理Service业务层处理
 *
 * @author xbts
 * @date 2023-08-29
 */
@Service
public class CnContractManagerServiceImpl extends ServiceImpl<CnContractManagerMapper, CnContractManager> implements ICnContractManagerService {

    @Autowired
    private ICnContractOrderItemRelationService cnContractOrderItemRelationService;
    @Autowired
    private ICnOrderItemService cnOrderItemService;
    @Autowired
    private ICnContractTemplateService cnContractTemplateService;
    @Autowired
    private EmailSendService emailSendService;
    @Autowired
    private ISysMessageService sysMessageService;
    @Autowired
    private ISysUserService userService;


    @Autowired
    private ICnCompanyInformationService companyInformationService;



    /**
     * 查询合同管理列表
     *
     * @param cnContractManager 合同管理
     * @return 合同管理
     */
    @Override
    public List<CnContractManager> selectCnContractManagerList(CnContractManagerVO cnContractManager) {
        if(!SecurityUtils.isManager()){
            cnContractManager.setUserId(SecurityUtils.getUserId().toString());
        }

        Map<String, Object> params = cnContractManager.getParams();
        String startTime = (String) params.get("startTime");
        String endTime = (String) params.get("endTime");
        if(StringUtils.isNotBlank(startTime) || StringUtils.isNotBlank(endTime)){
            cnContractManager.setStartTime(startTime);
            cnContractManager.setEndTime(endTime);
        }

        return baseMapper.selectList(cnContractManager);
    }

    /**
     * 查询合同管理
     *
     * @param id 合同管理主键
     * @return 合同管理
     */
    @Override
    public CnContractManagerDTO selectCnContractManagerById(String id) {
        CnContractManager contractManager = getById(id);
        if (contractManager == null) {
            throw new ServiceException("合同不存在");
        }
        // 查询合同关联订单项
        List<CnContractOrderItemRelation> cnContractOrderItemRelations = cnContractOrderItemRelationService
                .list(new LambdaQueryWrapper<CnContractOrderItemRelation>().eq(CnContractOrderItemRelation::getContractId, id));
        if (CollectionUtils.isEmpty(cnContractOrderItemRelations)) {
            throw new ServiceException("合同关联订单项不存在");
        }
        List<Long> orderItemIds = cnContractOrderItemRelations.stream().map(CnContractOrderItemRelation::getOrderItemId).collect(Collectors.toList());
        // 查询订单项
        List<CnOrderItem> cnOrderItems = cnOrderItemService.listByIds(orderItemIds);
        if (CollectionUtils.isEmpty(cnOrderItems)) {
            throw new ServiceException("订单项不存在");
        }
        CnContractManagerDTO cnContractManagerDTO = new CnContractManagerDTO();
        BeanUtils.copyProperties(contractManager, cnContractManagerDTO);
        cnContractManagerDTO.setOrderItems(cnOrderItems);
        return cnContractManagerDTO;
    }

    /**
     * 新增合同管理
     *
     * @param cnContractManager 合同管理
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertCnContractManager(CnContractManagerDTO cnContractManager) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (CollectionUtils.isEmpty(cnContractManager.getOrderItemIds())) {
            throw new ServiceException("订单ids不能为空");
        }
        // 查询订单
        List<CnOrderItem> cnOrderItems = cnOrderItemService.listByIds(cnContractManager.getOrderItemIds());
        if (CollectionUtils.isEmpty(cnOrderItems)) {
            throw new ServiceException("订单不存在");
        } else {
            for (CnOrderItem cnOrderItem : cnOrderItems) {
                if(StringUtils.equals(cnOrderItem.getContractStatus(),"1") || StringUtils.equals(cnOrderItem.getContractStatus(),"2")){
                    throw new ServiceException("订单已申请或创建合同！");
                }
                if(!cnOrderItem.getOrderStatus().equals(OrderStatusEnum.SUCCESS)){
                    throw new ServiceException("订单状态异常！");
                }
            }
        }
        // 判断合同中的订单类型是否一致
        List<ShoppingCarEnums> types = cnOrderItems.stream().map(CnOrderItem::getShoppingCarEnums).distinct().collect(Collectors.toList());
        if (types.size() > 1){
            throw new ServiceException("所选订单类型不一致！");
        }
        // 判断合同中的订单属于几个人，如果大于一人则抛错
        List<Long> userIds = cnOrderItems.stream().map(CnOrderItem::getUserId).distinct().collect(Collectors.toList());
        if (userIds.size() > 1){
            throw new ServiceException("不能同时给多个用户开具合同！");
        }

        BigDecimal totalUpdatePrice = BigDecimal.ZERO; // 总修改后价格
        for (CnOrderItem cnOrderItem : cnOrderItems) {
            totalUpdatePrice = totalUpdatePrice.add(cnOrderItem.getUpdatePrice());
        }
        // 订单金额
        BigDecimal updatePrice = totalUpdatePrice;
        cnContractManager.setContractAmount(updatePrice);
        // 订单所有者
        cnContractManager.setUserId(userIds.get(0));
        cnContractManager.setCreateBy(loginUser.getUser().getNickName());
        cnContractManager.setShoppingCarEnums(types.get(0));

        cnContractManager.setOrderItemId(cnOrderItems.stream().map(CnOrderItem::getOrderItemId).collect(Collectors.joining(",")));
        cnContractManager.setOrderItemSn(cnOrderItems.stream().map(CnOrderItem::getSn).distinct().collect(Collectors.joining(",")));

        // 管理员创建合同
        if (loginUser.getUser().getUserType().equals(UserConstants.USER_TYPE_MANAGER)) {
            if (StringUtils.isEmpty(cnContractManager.getAttachment())) {
                throw new ServiceException("请上传合同附件");
            }
            // 管理员创建合同，直接设置为通过
            cnContractManager.setContractStatus("2");
            cnContractManager.setHandledBy(SecurityUtils.getLoginUser().getUser().getNickName());
            cnContractManager.setCreateBy(SecurityUtils.getUserId().toString());
            CnCompanyInformation companyInformation = companyInformationService.getById(2);
            // 设置公司信息
            if (companyInformation != null) {
                cnContractManager.setCompanyAddress(companyInformation.getAddress());
                cnContractManager.setCompanyAccountNumber(companyInformation.getCompanyAccountNumber());
                cnContractManager.setCompanyContactPhone(companyInformation.getContactPhone());
                cnContractManager.setCompanyName(companyInformation.getContactUser());
            }
        } else {
            cnContractManager.setContractStatus("0");
        }

        // 修改订单合同状态
        LambdaUpdateWrapper<CnOrderItem> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(CnOrderItem::getOrderItemId, cnContractManager.getOrderItemIds());
        if (loginUser.getUser().getUserType().equals(UserConstants.USER_TYPE_MANAGER)) {
            updateWrapper.set(CnOrderItem::getContractStatus, "2");
        } else {
            updateWrapper.set(CnOrderItem::getContractStatus, "1");
        }
        // 修改订单合同状态
        cnOrderItemService.update(updateWrapper);
        save(cnContractManager);
        // 关联合同和子订单关系
        cnContractOrderItemRelationService.saveBatch(cnContractManager.getOrderItemIds().stream().map(orderItemId -> {
            CnContractOrderItemRelation cnContractOrderItemRelation = new CnContractOrderItemRelation();
            cnContractOrderItemRelation.setContractId(cnContractManager.getId());
            cnContractOrderItemRelation.setOrderItemId(orderItemId);
            return cnContractOrderItemRelation;
        }).collect(Collectors.toList()));
        return true;
    }

    /**
     * 修改合同管理
     *
     * @param cnContractManager 合同管理
     * @return 结果
     */
    @Override
    public boolean updateCnContractManager(CnContractManager cnContractManager) {
        cnContractManager.setUpdateBy(SecurityUtils.getUserId().toString());
        cnContractManager.setUpdateTime(DateUtils.getNowDate());
        return updateById(cnContractManager);
    }

    /**
     * 批量删除合同管理
     *
     * @param ids 需要删除的合同管理主键
     * @return 结果
     */
    @Override
    @Transactional
    public boolean deleteCnContractManagerByIds(List<String> ids) {
        for (String id : ids) {
            cancel(id);
        }
        return true;
    }

    /**
     * 删除合同管理信息
     *
     * @param id 合同管理主键
     * @return 结果
     */
    @Transactional
    @Override
    public boolean deleteCnContractManagerById(String id) {
        return removeById(id);
    }

    @Override
    public List<CnOrderItem> orderList(String shoppingCarEnums) {
        if (StringUtils.isEmpty(shoppingCarEnums)) {
            throw new ServiceException("请选择合同的订单类型");
        }
        List<String> status = new ArrayList<>();
        status.add("-1"); // 申请中
        status.add("0"); // 待开
        status.add("3"); // 拒绝
        LambdaQueryWrapper<CnOrderItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(CnOrderItem::getContractStatus, status);
        queryWrapper.eq(StringUtils.isNotNull(shoppingCarEnums), CnOrderItem::getShoppingCarEnums, shoppingCarEnums);
        queryWrapper.exists("select 1 from cn_order where cn_order.order_id = cn_order_item.order_id and cn_order.order_status = 'SUCCESS'");
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (!loginUser.getUser().getUserType().equals(UserConstants.USER_TYPE_MANAGER)) {
            queryWrapper.eq(CnOrderItem::getUserId, SecurityUtils.getUserId());
        }
        return cnOrderItemService.list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancel(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new ServiceException("合同id不能为空!");
        }

        LambdaQueryWrapper<CnContractOrderItemRelation> relationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        relationLambdaQueryWrapper.eq(CnContractOrderItemRelation::getContractId, id);


        CnContractManager cnContractManager = this.getById(id);
        cnContractManager.setCancel(true);
        updateById(cnContractManager);

        // 发送消息
        SysMessage message = new SysMessage();
        String title = "合同作废通知";
        String content = "编号为：【" + id + "】的合同已于" + DateUtils.getTime() + "作废。";
        message.setUserIds(Collections.singletonList(cnContractManager.getUserId()));
        message.setNoticeType(2);
        message.setNoticeTitle(title);
        message.setNoticeContent(content);
        message.setIsAll(1);
        sysMessageService.addSysMessage(message);

        // 发送邮件
        //获取用户邮箱地址
        String email = userService.getEmailByUserId(cnContractManager.getUserId());
        emailSendService.sendMessage(new EmailSendDTO(email, title, EmailTypeEnum.CONTRACT_INVALIDATION,id,DateUtils.getTime()));

        List<CnContractOrderItemRelation> lst = cnContractOrderItemRelationService.list(relationLambdaQueryWrapper);
        List<Long> orderIds = lst.stream().map(CnContractOrderItemRelation::getOrderItemId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(orderIds)) {
            return true;
        }
        // 更新订单开票的状态
        LambdaUpdateWrapper<CnOrderItem> orderUpdateWrapper = new LambdaUpdateWrapper<>();
        orderUpdateWrapper.in(CnOrderItem::getOrderItemId, orderIds);
        orderUpdateWrapper.set(CnOrderItem::getContractStatus, "0");
        cnOrderItemService.update(orderUpdateWrapper);

        // 删除合同和订单的关系
        cnContractOrderItemRelationService.remove(relationLambdaQueryWrapper);

        return true;

    }

    /**
     * 下载合同
     * @param response 响应
     * @param ids 合同id数组
     */
    @Override
    public void download(HttpServletResponse response, List<String> ids) {
        if (StringUtils.isNull(ids)) {
            throw new ServiceException("子订单id不能为空!");
        }
//        List<CnContractManager> cnContractManagers = baseMapper.selectCnContractManagerByOrderItemIds(ids);

        List<CnContractManager> cnContractManagers = listByIds(ids);
//        CnContractManager cnContractManager1 =  new CnContractManager();
//        BeanUtils.copyProperties(cnContractManagers.get(0), cnContractManager1);
//        cnContractManager1.setAttachment(null);
//        cnContractManager1.setCreateBy("22");
//        cnContractManagers.add(cnContractManager1);
        try {
            List<String> fileTypes = new ArrayList<>(ids.size());
            List<ByteArrayOutputStream> outputStreams = new ArrayList<>(ids.size());
            for (CnContractManager cnContractManager : cnContractManagers) {
                CnContractManagerDTO cnContractManagerDTO = new CnContractManagerDTO();
                BeanUtils.copyProperties(cnContractManager, cnContractManagerDTO);

                // 获取子订单项
                LambdaQueryWrapper<CnContractOrderItemRelation> relationLambdaQueryWrapper = new LambdaQueryWrapper<>();
                relationLambdaQueryWrapper.eq(CnContractOrderItemRelation::getContractId, cnContractManager.getId());
                List<CnContractOrderItemRelation> relationList = cnContractOrderItemRelationService.list(relationLambdaQueryWrapper);
                List<Long> orderItemsIds = relationList.stream().map(CnContractOrderItemRelation::getOrderItemId).collect(Collectors.toList());
                List<CnOrderItem> orderItems = cnOrderItemService.listByIds(orderItemsIds);
                if (CollectionUtils.isEmpty(orderItems)) {
                    throw new ServiceException("合同关联的订单不存在");
                }
                // 绑定合同和订单的关系
                cnContractManagerDTO.setOrderItems(orderItems);

                // 管理员上传的合同附件
                String attachment = cnContractManager.getAttachment();
                // 管理员创建的合同是文件地址，需要先将文件下载到本地
//                if (cnContractManager.getCreateBy().equals("1") && StringUtils.isNotEmpty(attachment)) {
//                    // 本地资源路径
//                    String localPath = XbtsConfig.getProfile();
//                    // 数据库资源地址
//                    String downloadPath = localPath + StringUtils.substringAfter(attachment, Constants.RESOURCE_PREFIX);
//                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//                    try {
//                        FileInputStream fileInputStream = new FileInputStream(downloadPath);
//                        if (fileInputStream.available() == 0) {
//                            throw new ServiceException("文件不存在");
//                        }
//                        IOUtils.copy(fileInputStream, byteArrayOutputStream);
//                        outputStreams.add(byteArrayOutputStream);
//                    } catch (IOException e) {
//                        log.error("下载合同附件失败", e);
//                    }
//                    fileTypes.add(StringUtils.substringAfterLast(attachment, "."));
//                    continue;
//                }  // 根据订单和合同生成word文档
                // 获取合同模板
                CnContractTemplate cnContractTemplate = cnContractTemplateService.getOne(new LambdaQueryWrapper<CnContractTemplate>().eq(CnContractTemplate::getShoppingCarEnums, cnContractManagerDTO.getOrderItems().get(0).getShoppingCarEnums()));
                ByteArrayOutputStream word = WordUtils.createWord(cnContractManagerDTO, cnContractTemplate.getContent(), cnContractManagerDTO.getOrderItems());
                // 保存至本地
//                fileOutputStream = new FileOutputStream(new File("D:/tmp/test.docx"));
//                IOUtils.copy(new ByteArrayInputStream(word.toByteArray()), fileOutputStream);
                fileTypes.add("docx");
                outputStreams.add(word);
            }

            response.setHeader("content-type", "application/octet-stream");
            response.setContentType("application/octet-stream");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");

            // 设置响应头
            if (!CollectionUtils.isEmpty(cnContractManagers)) {
                if (outputStreams.size() == 1) {
//                    String attachment = cnContractManagers.get(0).getAttachment();
//                    String fileName = StringUtils.substringAfterLast(attachment, "/");
                    response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("合同附件.docx", "UTF-8"));
                } else {
                    response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("合同附件.zip", "UTF-8"));
                }
            }
            createFile(outputStreams, response.getOutputStream(),fileTypes);
        } catch (IOException e) {
            log.error("下载合同附件失败", e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean pass(String orderItemId) {
        if (StringUtils.isEmpty(orderItemId)){
            throw new ServiceException("子订单id能为空");
        }
        return updateStatus(orderItemId, "2");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean refuse(String orderItemId) {
        if (StringUtils.isEmpty(orderItemId)){
            throw new ServiceException("子订单id能为空");
        }
        return updateStatus(orderItemId, "3");
    }

    /**
     * 更新合同和订单状态
     * @param orderItemId 子订单id
     * @param status 合同状态
     */
    private boolean updateStatus(String orderItemId, String status) {

        CnOrderItem cnOrderItem = new CnOrderItem();
        cnOrderItem.setOrderItemId(orderItemId);
        cnOrderItem.setContractStatus(status);
        cnOrderItem.setUpdateBy(SecurityUtils.getLoginUser().getUser().getNickName());

        cnOrderItemService.updateById(cnOrderItem);
        // 查询子订单和合同的关联表
        CnContractOrderItemRelation cnContractOrderItemRelation = new CnContractOrderItemRelation();
        cnContractOrderItemRelation.setOrderItemId(Long.valueOf(orderItemId));
        CnContractOrderItemRelation relationServiceOne = cnContractOrderItemRelationService.getOne(
                new LambdaQueryWrapper<CnContractOrderItemRelation>().eq(CnContractOrderItemRelation::getOrderItemId, orderItemId));
        if (null != relationServiceOne){
            CnContractManager contractManager = new CnContractManager();
            contractManager.setId(relationServiceOne.getContractId());
            contractManager.setContractStatus(status);
            contractManager.setHandledBy(SecurityUtils.getLoginUser().getUser().getNickName());
            return updateById(contractManager);
        }
        return false;
    }

    /**
     * 根据订单和合同生成word文档,并返回文件流, 一个文件返回文件本省，多个文件返回压缩包
     * @param outputStreams        文件流
     * @param responseOutputStream 响应流
     * @param fileTypes           文件类型
     */
    private void createFile(List<ByteArrayOutputStream> outputStreams, ServletOutputStream responseOutputStream, List<String> fileTypes) {
        try {
            if (outputStreams.size() == 1) {
                ByteArrayOutputStream byteArrayOutputStream = outputStreams.get(0);
                byte[] bytes = byteArrayOutputStream.toByteArray();
                IOUtils.copy(new ByteArrayInputStream(bytes), responseOutputStream);
            } else {
                // 压缩文件
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);
                for (int i = 0; i < outputStreams.size(); i++) {
                    ByteArrayOutputStream outputStream = outputStreams.get(i);
                    ZipEntry zipEntry = new ZipEntry("合同" + (i + 1) + "." + fileTypes.get(i));
                    try {
                        zipOutputStream.putNextEntry(zipEntry);
                        zipOutputStream.write(outputStream.toByteArray());
                        zipOutputStream.closeEntry();
                    } catch (IOException e) {
                        log.error("压缩文件失败", e);
                    }
                }
                try {
                    zipOutputStream.close();
                } catch (IOException e) {
                    log.error("压缩文件失败", e);
                }
                byte[] bytes = byteArrayOutputStream.toByteArray();
                IOUtils.copy(new ByteArrayInputStream(bytes), responseOutputStream);
            }
        } catch (IOException e) {
            log.error("下载合同附件失败", e);
        }
    }
}